--TEST--
PHP Spec test generated from ./variables/variable_variables.php
--FILE--
<?php

/*
   +-------------------------------------------------------------+
   | Copyright (c) 2014 Facebook, Inc. (http://www.facebook.com) |
   +-------------------------------------------------------------+
*/

error_reporting(-1);

///*
echo "================== simple cases ====================\n";

$color = "red";
echo "\$color = $color\n";

$$color = 123;			// 2 consecutive $s
echo "\$red = $red\n";	// ==> $red = 123
var_dump($$color);

echo "================== multiple expansion ====================\n";

$x = 'ab';
$ab = 'fg';
$fg = 'xy';

$$$$x = 'Hello';		// looks like a unary operator, and associates R->L
//$$$($x) = 'Hello';	// However, CAN'T use grouping parens to document that!!!
echo "\$xy = $xy\n";	// ==> $xy = Hello
$						// can have arbitrary white space separators
 $
 $ $x = 'Hello';
echo "\$xy = $xy\n";

${${${$x}}} = 'Hello';
echo "\$xy = $xy\n";

var_dump($x);
var_dump($ $x);
var_dump($ $ $x);
var_dump($ $ $ $x);
//*/

///*
echo "================== Using non-variable operands to $ ====================\n";

const CON = 'v';
//$CON = 5;				// seen as 1 token ($CON), not as $ and CON
//$ CON = 5;				// syntax error, unexpected 'CON' (T_STRING),
						// expecting variable (T_VARIABLE) or '$'

// Without the {}, the operand of $ must begin with a variable name (which
// excludes constants) // or another $
//*/

///*
echo "================== Use various scalar types as $'s operand ====================\n";

// $'s operand can be a value of any scalar type, but NOT a literal

// string operand

$v1 = 'abc';
$$v1 = '$v1 = \'abc\'';
echo "\$abc = $abc\n";
var_dump($$v1);

// int operand

$v2 = 3;
$$v2 = '$v2 = 3';
var_dump($$v2);
${$v2} = '$v2 = 3';
var_dump(${$v2});
//$3 = '$v2 = 3';
$ {  3  } = '$v2 = 3';
var_dump(${3});

// float operand

$v3 = 9.543;
$$v3 = '$v3 = 9.543';
var_dump($$v3);

// bool operand

$v4 = TRUE;
$$v4 = '$v4 = TRUE';
var_dump($$v4);
$v5 = FALSE;
$$v5 = '$v5 = FALSE';
var_dump($$v5);

// null operand

$v6 = NULL;
$$v6 = '$v6 = NULL';
var_dump($$v6);

//var_dump($GLOBALS);

function f()
{
	// the following work, but the name $'abc' is created in the local scope;
	// it certainly isn't in the Globals array. However, given the global declaration,
	// the name $'3' does designated the global by that name.

	$v11 = 'abc';
	$$v11 = '$v11 = \'abc\'';
	echo "\$abc = $abc\n";
	var_dump($$v11);

	global ${3};

	$v12 = 3;
	$$v12 = '$v12 = 3';		// changes the global
	var_dump($$v12);
}

f();

//var_dump($GLOBALS);
//*/

///*
echo "================== complex cases, [] ====================\n";

$v = array(10, 20);
$a = 'v';
$$a[0] = 5;				

var_dump($v);
unset($v, $a);

$v = array(10, 20);
$a = 'v';
${$a[0]} = 5;			
var_dump($v);
unset($v, $a);

$v = array(10, 20);
$a = 'v';
${$a}[0] = 5;			
var_dump($v);
unset($v, $a);
//*/

class C1
{
	public static $pr1 = 'v';
	public $pr2;

	public function __toString()
	{
		return 'w';
	}
}

///*
echo "================== complex cases, :: ====================\n";

var_dump(C1::$pr1);
${C1::$pr1} = 5;	// okay with {}
//$C1::$pr1 = 5;	// error: Undefined variable: C1, as longest token that can be formed
				// is $C1
//$ C1::$pr1 = 5;	// insert space so sees 2 tokens: $ and C1. error: syntax error,
				// unexpected 'C1' (T_STRING), expecting variable (T_VARIABLE) or '$'
				// Doesn't seem to accept a qualified name here (which would exclude a
				// namespace prefix as well)
var_dump($v);
unset($v);
//*/

///*
echo "================== complex cases, -> ====================\n";

$c1 = new C1;
$c1->pr2 = 'v';

var_dump($c1->pr2);
var_dump($c1);

$$c1->pr2 = 6;			// $w => stdClass { ["pr2"]=>int(6) }
//var_dump($GLOBALS);
${$c1}->pr2 = 7;		// $w => stdClass { ["pr2"]=>int(7) }
//var_dump($GLOBALS);

// The 2 cases above are equivalent. Here's what's happening:
// $c1 is converted to a string via __toString, which gives 'w'.
// The designated variable becomes $w, which does not exist, so it looks like
// it has a value of NULL. Then, when the -> is applied, we get a instance of stdClass.
// The problem then is that the $ operator takes precedence over the ->, which wasn't
// what I expected.

${$c1->pr2} = 8;		// $v = 8
//var_dump($GLOBALS);

unset($v, $w);
//*/

///*
echo "----------------------\n";

function ff() { return "xxx"; }

$res = ff();
$$res = 777;
echo "\$xxx = $xxx\n";
//*/
--EXPECTF--
================== simple cases ====================
$color = red
$red = 123
int(123)
================== multiple expansion ====================
$xy = Hello
$xy = Hello
$xy = Hello
string(2) "ab"
string(2) "fg"
string(2) "xy"
string(5) "Hello"
================== Using non-variable operands to $ ====================
================== Use various scalar types as $'s operand ====================
$abc = $v1 = 'abc'
string(11) "$v1 = 'abc'"
string(7) "$v2 = 3"
string(7) "$v2 = 3"
string(7) "$v2 = 3"
string(11) "$v3 = 9.543"
string(10) "$v4 = TRUE"
string(11) "$v5 = FALSE"
string(10) "$v6 = NULL"
$abc = $v11 = 'abc'
string(12) "$v11 = 'abc'"
string(8) "$v12 = 3"
================== complex cases, [] ====================
array(2) {
  [0]=>
  int(5)
  [1]=>
  int(20)
}
int(5)
array(2) {
  [0]=>
  int(5)
  [1]=>
  int(20)
}
================== complex cases, :: ====================
string(1) "v"
int(5)
================== complex cases, -> ====================
string(1) "v"
object(C1)#1 (1) {
  ["pr2"]=>
  string(1) "v"
}

Warning: Creating default object from empty value in %s/variables/variable_variables.php on line 183
----------------------
$xxx = 777
